package com.google.code.ojar.sendtemplatemail.app;

import java.util.List;

import org.apache.commons.mail.DefaultAuthenticator;
import org.apache.commons.mail.Email;
import org.apache.commons.mail.EmailAttachment;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import org.apache.commons.mail.MultiPartEmail;
import org.apache.commons.mail.SimpleEmail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.code.ojar.sendtemplatemail.app.dto.Attachment;
import com.google.code.ojar.sendtemplatemail.app.dto.Mail;
import com.google.code.ojar.sendtemplatemail.app.exception.AppException;
import com.google.code.ojar.sendtemplatemail.app.exception.MissingAddressException;
import com.google.code.ojar.sendtemplatemail.app.exception.MissingConfigurationException;
import com.google.code.ojar.sendtemplatemail.app.exception.SendMailException;
import com.google.code.ojar.sendtemplatemail.app.library.SendMailLibrary;
import com.google.code.ojar.sendtemplatemail.app.utils.SendMailUtils;

/**
 * Class in charge of preparing the msg to send
 * 
 * @author ottoabreu
 * 
 */
public final class SendMail {
	// logger
	private static final Logger logger = LoggerFactory
			.getLogger(SendMail.class);

	/**
	 * Sends the mail. Depends on the type it will prepare an
	 * {@link MultiPartEmail}, {@link HtmlEmail} or a {@link SimpleEmail}
	 * 
	 * @param mail
	 *            {@link Mail} object that holds the msg and properties
	 * @throws MissingAddressException
	 *             if no addresses where send
	 * @throws SendMailException
	 *             if some exception is thrown when a checked error occurs in
	 *             commons-email.
	 * @throws MissingConfigurationException
	 *             If the host is blank or null
	 */
	public static void send(Mail mail) throws MissingAddressException,
			SendMailException, MissingConfigurationException {

		// Establezco las propiedades
		// String protocol =
		// SendMailUtils.getPropertiesString(SendMailLibrary.PROPERTY_FILE_NAME,
		// SendMailLibrary.PROPERTY_KEY_MAIL_PROTOCOL);
		final String psw = SendMailUtils.getPropertiesString(
				SendMailLibrary.PROPERTY_FILE_NAME,
				SendMailLibrary.PROPERTY_KEY_MAIL_USERPW);
		final String user = SendMailUtils.getPropertiesString(
				SendMailLibrary.PROPERTY_FILE_NAME,
				SendMailLibrary.PROPERTY_KEY_MAIL_USER);
		final String host = SendMailUtils.getPropertiesString(
				SendMailLibrary.PROPERTY_FILE_NAME,
				SendMailLibrary.PROPERTY_KEY_MAIL_HOST);
		final String from = SendMailUtils.getPropertiesString(
				SendMailLibrary.PROPERTY_FILE_NAME,
				SendMailLibrary.PROPERTY_KEY_MAIL_FROM);
		final String port = SendMailUtils.getPropertiesString(
				SendMailLibrary.PROPERTY_FILE_NAME,
				SendMailLibrary.PROPERTY_KEY_MAIL_PORT);
		final String fromName = SendMailUtils.getPropertiesString(
				SendMailLibrary.PROPERTY_FILE_NAME,
				SendMailLibrary.PROPERTY_KEY_MAIL_FROM_NAME);
		Email email = null;

		if (host == null || host.equals("")) {

			logger.error(MissingConfigurationException.MISSING_VALUE_HOST);
			throw new MissingConfigurationException(
					MissingConfigurationException.MISSING_VALUE_HOST);
		}

		try {
			// verifico si es un mail con attch

			if (mail.getAttachments() != null
					&& !mail.getAttachments().isEmpty()) {
				logger.info("Creating multipart email with atachments");
				email = new MultiPartEmail();
				SendMail.setEmailProperties(email, host, port, user, psw,
						mail.getToAdds(), mail.getCcAdds(), mail.getBccAdds(),
						from, fromName, mail.getSubject());

				email.setMsg(mail.getMsg());

				for (Attachment attch : mail.getAttachments()) {
					EmailAttachment attachment = new EmailAttachment();
					attachment.setDescription(attch.getDescription());
					attachment.setDisposition(EmailAttachment.ATTACHMENT);
					attachment.setName(attch.getName());
					logger.info("adding atachment: " + attch.getName());
					if (attch.getPath() != null && !attch.getPath().equals("")) {

						logger.info("adding atachment path: " + attch.getPath());
						attachment.setPath(attch.getPath());
					} else {
						logger.info("the msg will not have "
								+ attch.getName()
								+ " / "
								+ attch.getDescription()
								+ " attached because no url or path was defined ");
					}
				}
				logger.info("Created multipart email with atachments");
			} else {
				// verifico si es un mail html
				if (mail.isHtmlMail()) {
					logger.info("Creating html email");
					email = new HtmlEmail();

					SendMail.setEmailProperties(email, host, port, user, psw,
							mail.getToAdds(), mail.getCcAdds(),
							mail.getBccAdds(), from, fromName,
							mail.getSubject());

					((HtmlEmail) email).setHtmlMsg(mail.getMsg());
					logger.info("Created html email");
				} else {
					logger.info("Creating simple text email");
					// es un correo de texto
					email = new SimpleEmail();
					SendMail.setEmailProperties(email, host, port, user, psw,
							mail.getToAdds(), mail.getCcAdds(),
							mail.getBccAdds(), from, fromName,
							mail.getSubject());
					email.setMsg(mail.getMsg());
					logger.info("Created simple text email");
				}

			}
			// envio el correo
			email.send();
			logger.info("mail send");
		} catch (EmailException e) {
			logger.error(SendMailException.SEND_MSG_ERROR, e);
			throw new SendMailException(SendMailException.SEND_MSG_ERROR, e);
		} catch (Exception e) {
			logger.error(AppException.GENERIC_ERROR, e);
			throw new AppException(AppException.GENERIC_ERROR, e);
		}

	}

	/**
	 * method that sets the required values to an email object
	 * 
	 * @param email
	 *            Email
	 * @param host
	 *            String
	 * @param port
	 *            String
	 * @param user
	 *            String
	 * @param pwd
	 *            String
	 * @param toAddr
	 *            List<String>
	 * @param ccAddr
	 *            List<String>
	 * @param bccAddr
	 *            List<String>
	 * @param from
	 *            String
	 * @param fromName
	 *            String
	 * @param Subject
	 *            String
	 * @throws EmailException
	 *             if some properties can't be set
	 * @throws MissingAddressException
	 *             if no toAddress is set
	 */
	private static void setEmailProperties(final Email email, final String host,
			final String port, final String user, String pwd, final List<String> toAddr,
			final List<String> ccAddr, final List<String> bccAddr, final String from,
			final String fromName, final String Subject) throws EmailException,
			MissingAddressException {
		// se establece el host
		email.setHostName(host);
		// verifico que se establecieran las direcciones de destinatario, caso
		// contrario envio una excepcion
		if (toAddr != null && !toAddr.isEmpty()) {
			for (String addr : toAddr) {
				logger.debug("la dir to: "+addr);
				email.addTo(addr);
			}
		} else {
			logger.error(MissingAddressException.MISSING_TO_ADDRESS + toAddr);
			throw new MissingAddressException(
					MissingAddressException.MISSING_TO_ADDRESS + toAddr);
		}
		// verifico que se establecieran las direcciones de copia
		if (ccAddr != null && !ccAddr.isEmpty()) {
			for (String addr : ccAddr) {
				logger.debug("la dir cc: "+addr);
				email.addCc(addr);
			}
		}
		// verifico que se establecieran las direcciones de copia oculta
		if (bccAddr != null && !bccAddr.isEmpty()) {
			for (String addr : bccAddr) {
				logger.debug("la dir bcc: "+addr);
				email.addBcc(addr);
			}
		}
		// verifico que exista un nombre a mostrar para la direccion desde
		if (fromName != null) {
			email.setFrom(from, fromName);
		} else {
			email.setFrom(from);
		}
		// verifico si el puerto ha sido establecido
		if (port != null && !port.equals("")) {
			email.setSmtpPort(Integer.parseInt(port));
		}
		// verifico si la conex necesita de un usuario
		if (user != null && !user.equals("")) {

			if (pwd == null) {
				pwd = "";
			}
			email.setAuthenticator(new DefaultAuthenticator(user, pwd));
		}
		// se establece el subject del correo
		email.setSubject(Subject);
	}
	/**
	 * Private constructor
	 */
	private SendMail(){
		
	}
}
